package com.zxmzy.scaffold.core.base

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zxmzy.scaffold.core.net.RequestDSL
import com.zxmzy.scaffold.core.net.error.ApiException
import com.zxmzy.scaffold.core.net.error.ExceptionHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * @author zhangxiaoming
 * @date 2023/8/2
 * @description
 */
abstract class BaseViewModel : ViewModel() {
    private val _loading = MutableLiveData<Boolean>()
    val loadingLiveData: LiveData<Boolean> get() = _loading
    private val _errorLiveData = MutableLiveData<ApiException>()
    val errorLiveData: LiveData<ApiException> get() = _errorLiveData

    protected fun <Response> launch(
        requestDSL: RequestDSL<Response>.() -> Unit
    ) {
        val request = RequestDSL<Response>().apply(requestDSL)
        viewModelScope.launch(context = Dispatchers.Main) {
            val startOverride = request.onStart?.invoke()
            if (startOverride == null || !startOverride) {
                onRequestStart()
            }
            try {
                val response = withContext(Dispatchers.IO) {
                    request.request()
                }
                request.onResponse?.invoke(response)
            } catch (e: Exception) {
                e.printStackTrace()
                onError(request, e)
            } finally {
                val finallyOverride = request.onFinally?.invoke()
                if (finallyOverride == null || !finallyOverride) {
                    onRequestFinally()
                }
            }
        }
    }

    private fun <Response> onError(request: RequestDSL<Response>, e: Throwable) {
        val apiException = ExceptionHandler.handleException(e)
        val errorOverride = request.onError?.invoke(apiException)
        if (errorOverride == null || !errorOverride) {
            onRequestError(apiException)
        }
    }

    protected open fun onRequestStart() {
        _loading.value = true
    }

    protected open fun onRequestError(e: ApiException) {
        _loading.value = false
        _errorLiveData.value = e
    }

    protected open fun onRequestFinally() {
        _loading.value = false
    }
}